home *** CD-ROM | disk | FTP | other *** search
/ PC/CD Gamer UK 120 / CD Gamer Issue 120 (March 2003) (Disc 2).ISO / mods / Q2_Codered / codeRED1_0.exe / Data1.cab / console.c < prev    next >
Encoding:
C/C++ Source or Header  |  2002-08-13  |  12.5 KB  |  683 lines

  1. /*
  2. Copyright (C) 1997-2001 Id Software, Inc.
  3.  
  4. This program is free software; you can redistribute it and/or
  5. modify it under the terms of the GNU General Public License
  6. as published by the Free Software Foundation; either version 2
  7. of the License, or (at your option) any later version.
  8.  
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
  12.  
  13. See the GNU General Public License for more details.
  14.  
  15. You should have received a copy of the GNU General Public License
  16. along with this program; if not, write to the Free Software
  17. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  18.  
  19. */
  20. // console.c
  21.  
  22. #include "client.h"
  23.  
  24. console_t    con;
  25.  
  26. cvar_t        *con_notifytime;
  27.  
  28.  
  29. #define        MAXCMDLINE    256
  30. extern    char    key_lines[32][MAXCMDLINE];
  31. extern    int        edit_line;
  32. extern    int        key_linepos;
  33.         
  34.  
  35. void DrawString (int x, int y, char *s)
  36. {
  37.     while (*s)
  38.     {
  39.         Draw_Char (x, y, *s);
  40.         x+=8;
  41.         s++;
  42.     }
  43. }
  44.  
  45. void DrawAltString (int x, int y, char *s)
  46. {
  47.     while (*s)
  48.     {
  49.         Draw_Char (x, y, *s ^ 0x80);
  50.         x+=8;
  51.         s++;
  52.     }
  53. }
  54.  
  55.  
  56. void Key_ClearTyping (void)
  57. {
  58.     key_lines[edit_line][1] = 0;    // clear any typing
  59.     key_linepos = 1;
  60. }
  61.  
  62. /*
  63. ================
  64. Con_ToggleConsole_f
  65. ================
  66. */
  67. void Con_ToggleConsole_f (void)
  68. {
  69.     SCR_EndLoadingPlaque ();    // get rid of loading plaque
  70.  
  71.     if (cl.attractloop)
  72.     {
  73.         Cbuf_AddText ("killserver\n");
  74.         return;
  75.     }
  76.  
  77.     if (cls.state == ca_disconnected)
  78.     {    // start the demo loop again
  79.         Cbuf_AddText ("d1\n");
  80.         return;
  81.     }
  82.  
  83.     Key_ClearTyping ();
  84.     Con_ClearNotify ();
  85.  
  86.     if (cls.key_dest == key_console)
  87.     {
  88.         M_ForceMenuOff ();
  89.         Cvar_Set ("paused", "0");
  90.     }
  91.     else
  92.     {
  93.         M_ForceMenuOff ();
  94.         cls.key_dest = key_console;    
  95.  
  96.         if (Cvar_VariableValue ("maxclients") == 1 
  97.             && Com_ServerState ())
  98.             Cvar_Set ("paused", "1");
  99.     }
  100. }
  101.  
  102. /*
  103. ================
  104. Con_ToggleChat_f
  105. ================
  106. */
  107. void Con_ToggleChat_f (void)
  108. {
  109.     Key_ClearTyping ();
  110.  
  111.     if (cls.key_dest == key_console)
  112.     {
  113.         if (cls.state == ca_active)
  114.         {
  115.             M_ForceMenuOff ();
  116.             cls.key_dest = key_game;
  117.         }
  118.     }
  119.     else
  120.         cls.key_dest = key_console;
  121.     
  122.     Con_ClearNotify ();
  123. }
  124.  
  125. /*
  126. ================
  127. Con_Clear_f
  128. ================
  129. */
  130. void Con_Clear_f (void)
  131. {
  132.     memset (con.text, ' ', CON_TEXTSIZE);
  133. }
  134.  
  135.                         
  136. /*
  137. ================
  138. Con_Dump_f
  139.  
  140. Save the console contents out to a file
  141. ================
  142. */
  143. void Con_Dump_f (void)
  144. {
  145.     int        l, x;
  146.     char    *line;
  147.     FILE    *f;
  148.     char    buffer[1024];
  149.     char    name[MAX_OSPATH];
  150.  
  151.     if (Cmd_Argc() != 2)
  152.     {
  153.         Com_Printf ("usage: condump <filename>\n");
  154.         return;
  155.     }
  156.  
  157.     Com_sprintf (name, sizeof(name), "%s/%s.txt", FS_Gamedir(), Cmd_Argv(1));
  158.  
  159.     Com_Printf ("Dumped console text to %s.\n", name);
  160.     FS_CreatePath (name);
  161.     f = fopen (name, "w");
  162.     if (!f)
  163.     {
  164.         Com_Printf ("ERROR: couldn't open.\n");
  165.         return;
  166.     }
  167.  
  168.     // skip empty lines
  169.     for (l = con.current - con.totallines + 1 ; l <= con.current ; l++)
  170.     {
  171.         line = con.text + (l%con.totallines)*con.linewidth;
  172.         for (x=0 ; x<con.linewidth ; x++)
  173.             if (line[x] != ' ')
  174.                 break;
  175.         if (x != con.linewidth)
  176.             break;
  177.     }
  178.  
  179.     // write the remaining lines
  180.     buffer[con.linewidth] = 0;
  181.     for ( ; l <= con.current ; l++)
  182.     {
  183.         line = con.text + (l%con.totallines)*con.linewidth;
  184.         strncpy (buffer, line, con.linewidth);
  185.         for (x=con.linewidth-1 ; x>=0 ; x--)
  186.         {
  187.             if (buffer[x] == ' ')
  188.                 buffer[x] = 0;
  189.             else
  190.                 break;
  191.         }
  192.         for (x=0; buffer[x]; x++)
  193.             buffer[x] &= 0x7f;
  194.  
  195.         fprintf (f, "%s\n", buffer);
  196.     }
  197.  
  198.     fclose (f);
  199. }
  200.  
  201.                         
  202. /*
  203. ================
  204. Con_ClearNotify
  205. ================
  206. */
  207. void Con_ClearNotify (void)
  208. {
  209.     int        i;
  210.     
  211.     for (i=0 ; i<NUM_CON_TIMES ; i++)
  212.         con.times[i] = 0;
  213. }
  214.  
  215.                         
  216. /*
  217. ================
  218. Con_MessageMode_f
  219. ================
  220. */
  221. void Con_MessageMode_f (void)
  222. {
  223.     chat_team = false;
  224.     cls.key_dest = key_message;
  225. }
  226.  
  227. /*
  228. ================
  229. Con_MessageMode2_f
  230. ================
  231. */
  232. void Con_MessageMode2_f (void)
  233. {
  234.     chat_team = true;
  235.     cls.key_dest = key_message;
  236. }
  237.  
  238. /*
  239. ================
  240. Con_CheckResize
  241.  
  242. If the line width has changed, reformat the buffer.
  243. ================
  244. */
  245. void Con_CheckResize (void)
  246. {
  247.     int        i, j, width, oldwidth, oldtotallines, numlines, numchars;
  248.     char    tbuf[CON_TEXTSIZE];
  249.  
  250.     width = (viddef.width >> 3) - 2;
  251.  
  252.     if (width == con.linewidth)
  253.         return;
  254.  
  255.     if (width < 1)            // video hasn't been initialized yet
  256.     {
  257.         width = 38;
  258.         con.linewidth = width;
  259.         con.totallines = CON_TEXTSIZE / con.linewidth;
  260.         memset (con.text, ' ', CON_TEXTSIZE);
  261.     }
  262.     else
  263.     {
  264.         oldwidth = con.linewidth;
  265.         con.linewidth = width;
  266.         oldtotallines = con.totallines;
  267.         con.totallines = CON_TEXTSIZE / con.linewidth;
  268.         numlines = oldtotallines;
  269.  
  270.         if (con.totallines < numlines)
  271.             numlines = con.totallines;
  272.  
  273.         numchars = oldwidth;
  274.     
  275.         if (con.linewidth < numchars)
  276.             numchars = con.linewidth;
  277.  
  278.         memcpy (tbuf, con.text, CON_TEXTSIZE);
  279.         memset (con.text, ' ', CON_TEXTSIZE);
  280.  
  281.         for (i=0 ; i<numlines ; i++)
  282.         {
  283.             for (j=0 ; j<numchars ; j++)
  284.             {
  285.                 con.text[(con.totallines - 1 - i) * con.linewidth + j] =
  286.                         tbuf[((con.current - i + oldtotallines) %
  287.                               oldtotallines) * oldwidth + j];
  288.             }
  289.         }
  290.  
  291.         Con_ClearNotify ();
  292.     }
  293.  
  294.     con.current = con.totallines - 1;
  295.     con.display = con.current;
  296. }
  297.  
  298.  
  299. /*
  300. ================
  301. Con_Init
  302. ================
  303. */
  304. void Con_Init (void)
  305. {
  306.     con.linewidth = -1;
  307.  
  308.     Con_CheckResize ();
  309.     
  310.     Com_Printf ("Console initialized.\n");
  311.  
  312. //
  313. // register our commands
  314. //
  315.     con_notifytime = Cvar_Get ("con_notifytime", "3", 0);
  316.  
  317.     Cmd_AddCommand ("toggleconsole", Con_ToggleConsole_f);
  318.     Cmd_AddCommand ("togglechat", Con_ToggleChat_f);
  319.     Cmd_AddCommand ("messagemode", Con_MessageMode_f);
  320.     Cmd_AddCommand ("messagemode2", Con_MessageMode2_f);
  321.     Cmd_AddCommand ("clear", Con_Clear_f);
  322.     Cmd_AddCommand ("condump", Con_Dump_f);
  323.     con.initialized = true;
  324. }
  325.  
  326.  
  327. /*
  328. ===============
  329. Con_Linefeed
  330. ===============
  331. */
  332. void Con_Linefeed (void)
  333. {
  334.     con.x = 0;
  335.     if (con.display == con.current)
  336.         con.display++;
  337.     con.current++;
  338.     memset (&con.text[(con.current%con.totallines)*con.linewidth]
  339.     , ' ', con.linewidth);
  340. }
  341.  
  342. /*
  343. ================
  344. Con_Print
  345.  
  346. Handles cursor positioning, line wrapping, etc
  347. All console printing must go through this in order to be logged to disk
  348. If no console is visible, the text will appear at the top of the game window
  349. ================
  350. */
  351. void Con_Print (char *txt)
  352. {
  353.     int        y;
  354.     int        c, l;
  355.     static int    cr;
  356.     int        mask;
  357.  
  358.     if (!con.initialized)
  359.         return;
  360.  
  361.     if (txt[0] == 1 || txt[0] == 2)
  362.     {
  363.         mask = 128;        // go to colored text
  364.         txt++;
  365.     }
  366.     else
  367.         mask = 0;
  368.  
  369.  
  370.     while ( (c = *txt) )
  371.     {
  372.     // count word length
  373.         for (l=0 ; l< con.linewidth ; l++)
  374.             if ( txt[l] <= ' ')
  375.                 break;
  376.  
  377.     // word wrap
  378.         if (l != con.linewidth && (con.x + l > con.linewidth) )
  379.             con.x = 0;
  380.  
  381.         txt++;
  382.  
  383.         if (cr)
  384.         {
  385.             con.current--;
  386.             cr = false;
  387.         }
  388.  
  389.         
  390.         if (!con.x)
  391.         {
  392.             Con_Linefeed ();
  393.         // mark time for transparent overlay
  394.             if (con.current >= 0)
  395.                 con.times[con.current % NUM_CON_TIMES] = cls.realtime;
  396.         }
  397.  
  398.         switch (c)
  399.         {
  400.         case '\n':
  401.             con.x = 0;
  402.             break;
  403.  
  404.         case '\r':
  405.             con.x = 0;
  406.             cr = 1;
  407.             break;
  408.  
  409.         default:    // display character and advance
  410.             y = con.current % con.totallines;
  411.             con.text[y*con.linewidth+con.x] = c | mask | con.ormask;
  412.             con.x++;
  413.             if (con.x >= con.linewidth)
  414.                 con.x = 0;
  415.             break;
  416.         }
  417.         
  418.     }
  419. }
  420.  
  421.  
  422. /*
  423. ==============
  424. Con_CenteredPrint
  425. ==============
  426. */
  427. void Con_CenteredPrint (char *text)
  428. {
  429.     int        l;
  430.     char    buffer[1024];
  431.  
  432.     l = strlen(text);
  433.     l = (con.linewidth-l)/2;
  434.     if (l < 0)
  435.         l = 0;
  436.     memset (buffer, ' ', l);
  437.     strcpy (buffer+l, text);
  438.     strcat (buffer, "\n");
  439.     Con_Print (buffer);
  440. }
  441.  
  442. /*
  443. ==============================================================================
  444.  
  445. DRAWING
  446.  
  447. ==============================================================================
  448. */
  449.  
  450.  
  451. /*
  452. ================
  453. Con_DrawInput
  454.  
  455. The input line scrolls horizontally if typing goes beyond the right edge
  456. ================
  457. */
  458. void Con_DrawInput (void)
  459. {
  460.     int        y;
  461.     int        i;
  462.     char    *text;
  463.  
  464.     if (cls.key_dest == key_menu)
  465.         return;
  466.     if (cls.key_dest != key_console && cls.state == ca_active)
  467.         return;        // don't draw anything (always draw if not active)
  468.  
  469.     text = key_lines[edit_line];
  470.     
  471. // add the cursor frame
  472.     text[key_linepos] = 10+((int)(cls.realtime>>8)&1);
  473.     
  474. // fill out remainder with spaces
  475.     for (i=key_linepos+1 ; i< con.linewidth ; i++)
  476.         text[i] = ' ';
  477.         
  478. //    prestep if horizontally scrolling
  479.     if (key_linepos >= con.linewidth)
  480.         text += 1 + key_linepos - con.linewidth;
  481.         
  482. // draw it
  483.     y = con.vislines-16;
  484.  
  485.     for (i=0 ; i<con.linewidth ; i++)
  486.         Draw_Char ( (i+1)<<3, con.vislines - 22, text[i]);
  487.  
  488. // remove cursor
  489.     key_lines[edit_line][key_linepos] = 0;
  490. }
  491.  
  492.  
  493. /*
  494. ================
  495. Con_DrawNotify
  496.  
  497. Draws the last few lines of output transparently over the game top
  498. ================
  499. */
  500. void Con_DrawNotify (void)
  501. {
  502.     int        x, v;
  503.     char    *text;
  504.     int        i;
  505.     int        time;
  506.     char    *s;
  507.     int        skip;
  508.  
  509.     v = 0;
  510.     for (i= con.current-NUM_CON_TIMES+1 ; i<=con.current ; i++)
  511.     {
  512.         if (i < 0)
  513.             continue;
  514.         time = con.times[i % NUM_CON_TIMES];
  515.         if (time == 0)
  516.             continue;
  517.         time = cls.realtime - time;
  518.         if (time > con_notifytime->value*1000)
  519.             continue;
  520.         text = con.text + (i % con.totallines)*con.linewidth;
  521.         
  522.         for (x = 0 ; x < con.linewidth ; x++)
  523.             Draw_Char ( (x+1)<<3, v, text[x]);
  524.  
  525.         v += 8;
  526.     }
  527.  
  528.  
  529.     if (cls.key_dest == key_message)
  530.     {
  531.         if (chat_team)
  532.         {
  533.             DrawString (8, v, "say_team:");
  534.             skip = 11;
  535.         }
  536.         else
  537.         {
  538.             DrawString (8, v, "say:");
  539.             skip = 5;
  540.         }
  541.  
  542.         s = chat_buffer;
  543.         if (chat_bufferlen > (viddef.width>>3)-(skip+1))
  544.             s += chat_bufferlen - ((viddef.width>>3)-(skip+1));
  545.         x = 0;
  546.         while(s[x])
  547.         {
  548.             Draw_Char ( (x+skip)<<3, v, s[x]);
  549.             x++;
  550.         }
  551.         Draw_Char ( (x+skip)<<3, v, 10+((cls.realtime>>8)&1));
  552.         v += 8;
  553.     }
  554.     
  555.     if (v)
  556.     {
  557.         SCR_AddDirtyPoint (0,0);
  558.         SCR_AddDirtyPoint (viddef.width-1, v);
  559.     }
  560. }
  561.  
  562. /*
  563. ================
  564. Con_DrawConsole
  565.  
  566. Draws the console with the solid background
  567. ================
  568. */
  569. void Con_DrawConsole (float frac)
  570. {
  571.     int                i, j, x, y, n;
  572.     int                rows;
  573.     char            *text;
  574.     int                row;
  575.     int                lines;
  576.     char            version[64];
  577.     char            dlbar[1024];
  578.  
  579.     lines = viddef.height * frac;
  580.     if (lines <= 0)
  581.         return;
  582.  
  583.     if (lines > viddef.height)
  584.         lines = viddef.height;
  585.  
  586. // draw the background
  587.     Draw_StretchPic (0, lines-viddef.height, viddef.width, viddef.height, "conback");
  588.     SCR_AddDirtyPoint (0,0);
  589.     SCR_AddDirtyPoint (viddef.width-1,lines-1);
  590.  
  591.     Com_sprintf (version, sizeof(version), "v%4.2f", VERSION);
  592.     for (x=0 ; x<5 ; x++)
  593.         Draw_Char (viddef.width-44+x*8, lines-12, 128 + version[x] );
  594.  
  595. // draw the text
  596.     con.vislines = lines;
  597.     
  598. #if 0
  599.     rows = (lines-8)>>3;        // rows of text to draw
  600.  
  601.     y = lines - 24;
  602. #else
  603.     rows = (lines-22)>>3;        // rows of text to draw
  604.  
  605.     y = lines - 30;
  606. #endif
  607.  
  608. // draw from the bottom up
  609.     if (con.display != con.current)
  610.     {
  611.     // draw arrows to show the buffer is backscrolled
  612.         for (x=0 ; x<con.linewidth ; x+=4)
  613.             Draw_Char ( (x+1)<<3, y, '^');
  614.     
  615.         y -= 8;
  616.         rows--;
  617.     }
  618.     
  619.     row = con.display;
  620.     for (i=0 ; i<rows ; i++, y-=8, row--)
  621.     {
  622.         if (row < 0)
  623.             break;
  624.         if (con.current - row >= con.totallines)
  625.             break;        // past scrollback wrap point
  626.             
  627.         text = con.text + (row % con.totallines)*con.linewidth;
  628.  
  629.         for (x=0 ; x<con.linewidth ; x++)
  630.             Draw_Char ( (x+1)<<3, y, text[x]);
  631.     }
  632.  
  633. //ZOID
  634.     // draw the download bar
  635.     // figure out width
  636.     if (cls.download) {
  637.         if ((text = strrchr(cls.downloadname, '/')) != NULL)
  638.             text++;
  639.         else
  640.             text = cls.downloadname;
  641.  
  642.         x = con.linewidth - ((con.linewidth * 7) / 40);
  643.         y = x - strlen(text) - 8;
  644.         i = con.linewidth/3;
  645.         if (strlen(text) > i) {
  646.             y = x - i - 11;
  647.             strncpy(dlbar, text, i);
  648.             dlbar[i] = 0;
  649.             strcat(dlbar, "...");
  650.         } else
  651.             strcpy(dlbar, text);
  652.         strcat(dlbar, ": ");
  653.         i = strlen(dlbar);
  654.         dlbar[i++] = '\x80';
  655.         // where's the dot go?
  656.         if (cls.downloadpercent == 0)
  657.             n = 0;
  658.         else
  659.             n = y * cls.downloadpercent / 100;
  660.             
  661.         for (j = 0; j < y; j++)
  662.             if (j == n)
  663.                 dlbar[i++] = '\x83';
  664.             else
  665.                 dlbar[i++] = '\x81';
  666.         dlbar[i++] = '\x82';
  667.         dlbar[i] = 0;
  668.  
  669.         sprintf(dlbar + strlen(dlbar), " %02d%%", cls.downloadpercent);
  670.  
  671.         // draw it
  672.         y = con.vislines-12;
  673.         for (i = 0; i < strlen(dlbar); i++)
  674.             Draw_Char ( (i+1)<<3, y, dlbar[i]);
  675.     }
  676. //ZOID
  677.  
  678. // draw the input prompt, user text, and cursor if desired
  679.     Con_DrawInput ();
  680. }
  681.  
  682.  
  683.